﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;

namespace MiniTool
{
    /// <summary>
    /// dll工具
    /// </summary>
    public class DLLUtil
    {
        /// <summary>
        /// 获取当前执行代码的程序集。
        /// </summary>
        /// <returns>当前执行代码的程序集。</returns>
        public static Assembly GetExecutingAssembly()
        {
            return Assembly.GetExecutingAssembly();
        }

        /// <summary>
        /// 获取调用当前方法的程序集。
        /// </summary>
        /// <returns>调用当前方法的程序集。</returns>
        public static Assembly GetCallingAssembly()
        {
            return Assembly.GetCallingAssembly();
        }

        /// <summary>
        /// 获取应用程序的入口程序集。
        /// </summary>
        /// <returns>应用程序的入口程序集。</returns>
        public static Assembly? GetEntryAssembly()
        {
            return Assembly.GetEntryAssembly();
        }

        /// <summary>
        /// 根据文件路径加载 DLL 程序集，并返回一个 Assembly 对象
        /// </summary>
        /// <param name="dllFilePath">DLL 文件路径</param>
        /// <returns>返回一个 Assembly 对象</returns>
        public static Assembly LoadAssembly(string dllFilePath)
        {
            return Assembly.LoadFile(dllFilePath);
        }

        /// <summary>
        /// 根据类型名称从程序集中获取 Type 对象
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="typeName">类型名称</param>
        /// <returns>返回 Type 对象</returns>
        public static Type? GetTypeFromAssembly(Assembly assembly, string typeName)
        {
            return assembly.GetType(typeName);
        }

        /// <summary>
        /// 创建指定类型的实例，并返回一个 Object 对象
        /// </summary>
        /// <param name="type">要创建实例的类型</param>
        /// <param name="parameters">实例化类型所需要的参数</param>
        /// <returns>返回创建的实例对象</returns>
        public static object? CreateInstance(Type type, params object[] parameters)
        {
            return Activator.CreateInstance(type, parameters);
        }

        /// <summary>
        /// 根据类型名称创建实例，并返回一个 Object 对象
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="typeName">类型名称</param>
        /// <param name="parameters">实例化类型所需要的参数</param>
        /// <returns>返回创建的实例对象</returns>
        public static object? CreateInstanceFromAssembly(Assembly assembly, string typeName, params object[] parameters)
        {
            Type? type = GetTypeFromAssembly(assembly, typeName);
            if (type != null)
            {
                return CreateInstance(type, parameters);
            }
            return null;
        }

        /// <summary>
        /// 调用对象的方法，并返回调用结果
        /// </summary>
        /// <param name="instance">要调用方法的对象</param>
        /// <param name="methodName">方法名称</param>
        /// <param name="parameters">方法所需要的参数</param>
        /// <returns>返回调用结果</returns>
        public static object? InvokeMethod(object instance, string methodName, params object[] parameters)
        {
            Type type = instance.GetType();
            MethodInfo? methodInfo = type.GetMethod(methodName);
            if (methodInfo != null)
            {
                return methodInfo.Invoke(instance, parameters);
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 获取程序集中所有的类型信息
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <returns>返回 Type[] 数组，数组中每个元素代表程序集中的一个类型</returns>
        public static Type[] GetAllTypesFromAssembly(Assembly assembly)
        {
            return assembly.GetTypes();
        }

        /// <summary>
        /// 获取当前项目中所有的程序集。
        /// </summary>
        /// <returns>当前项目中所有的程序集。</returns>
        public static List<Assembly> GetCurrentProjectAssemblies()
        {
            // 获取当前执行代码的程序集
            Assembly callingAssembly = Assembly.GetCallingAssembly();

            // 获取当前项目引用的所有程序集
            AssemblyName[] referencedAssemblies = callingAssembly.GetReferencedAssemblies();

            // 加载所有引用的程序集
            List<Assembly> projectAssemblies = new List<Assembly>();

            foreach (AssemblyName assemblyName in referencedAssemblies)
            {
                try
                {
                    Assembly assembly = Assembly.Load(assemblyName);
                    projectAssemblies.Add(assembly);
                }
                catch (Exception ex)
                {
                    // 处理程序集加载异常
                    throw new Exception($"Failed to load assembly '{assemblyName.FullName}': {ex.Message}");
                }
            }

            // 添加当前执行代码的程序集
            projectAssemblies.Add(callingAssembly);

            return projectAssemblies;
        }

        /// <summary>
        /// 判断指定类型是否实现了指定的接口
        /// </summary>
        /// <param name="type">要判断的类型</param>
        /// <param name="interfaceType">要判断的接口类型</param>
        /// <returns>返回布尔值，表示指定类型是否实现了指定的接口</returns>
        public static bool IsImplementInterface(Type type, Type interfaceType)
        {
            return interfaceType.IsAssignableFrom(type);
        }


        /// <summary>
        /// 从指定目录中加载所有的 DLL 文件，并返回一个 Assembly[] 数组
        /// </summary>
        /// <param name="directory">要加载 DLL 文件的目录</param>
        /// <returns>返回一个 Assembly[] 数组，数组中每个元素代表一个 DLL 程序集</returns>
        public static Assembly[] LoadAllDllsFromDirectory(string directory)
        {
            try
            {
                if (!Directory.Exists(directory))
                {
                    throw new DirectoryNotFoundException("LoadAllDllsFromDirectory Error: Directory not exist.");
                }

                string[] dllFiles = Directory.GetFiles(directory, "*.dll");
                if (dllFiles.Length == 0)
                {
                    throw new FileNotFoundException("LoadAllDllsFromDirectory Error: No DLL file found.");
                }

                Assembly[] assemblies = new Assembly[dllFiles.Length];
                for (int i = 0; i < dllFiles.Length; i++)
                {
                    assemblies[i] = LoadAssembly(dllFiles[i]);
                }
                return assemblies;
            }
            catch (Exception ex)
            {
                throw new Exception("LoadAllDllsFromDirectory Error: " + ex.Message);
            }
        }

        /// <summary>
        /// 获取指定程序集中的所有类型名称列表。
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <returns>返回类型名称列表</returns>
        public static List<string> GetAllTypeNamesFromAssembly(Assembly assembly)
        {
            Type[] types = assembly.GetTypes();
            List<string> typeNames = new List<string>();
            for (int i = 0; i < types.Length; i++)
            {
                Type type = types[i];
                if (type.FullName != null)
                {
                    typeNames.Add(type.FullName);
                }
            }
            return typeNames;
        }

        /// <summary>
        /// 根据类型名称判断指定的类型是否存在于指定的程序集中。
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="typeName">类型名称</param>
        /// <returns>返回布尔值，表示指定的类型是否存在于程序集中</returns>
        public static bool IsTypeExistInAssembly(Assembly assembly, string typeName)
        {
            Type? type = assembly.GetType(typeName);
            return type != null;
        }

        /// <summary>
        /// 获取指定程序集中实现了指定接口的所有类型。
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="interfaceType">接口类型</param>
        /// <returns>返回实现了指定接口的类型列表</returns>
        public static List<Type> GetTypesImplementingInterface(Assembly assembly, Type interfaceType)
        {
            Type[] types = assembly.GetTypes();
            List<Type> implementingTypes = new List<Type>();
            for (int i = 0; i < types.Length; i++)
            {
                Type type = types[i];
                if (interfaceType.IsAssignableFrom(type))
                {
                    implementingTypes.Add(type);
                }
            }
            return implementingTypes;
        }

        /// <summary>
        /// 获取指定程序集中实现了指定接口的所有类型。
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="interfaceTypeName">接口类型的完全限定名</param>
        /// <returns>返回实现了指定接口的类型列表</returns>
        public static List<Type> GetTypesImplementingInterface(Assembly assembly, string interfaceTypeName)
        {
            Type? interfaceType = Type.GetType(interfaceTypeName);
            if (interfaceType == null || !interfaceType.IsInterface)
            {
                throw new ArgumentException("Invalid interface type.");
            }

            Type[] types = assembly.GetTypes();
            List<Type> implementingTypes = new List<Type>();
            for (int i = 0; i < types.Length; i++)
            {
                Type type = types[i];
                if (interfaceType.IsAssignableFrom(type))
                {
                    implementingTypes.Add(type);
                }
            }
            return implementingTypes;
        }

        /// <summary>
        /// 获取给定程序集中的所有公共方法。
        /// </summary>
        /// <param name="assembly">要获取方法的程序集</param>
        /// <returns>包含所有公共方法的列表</returns>
        public static List<MethodInfo> GetPublicMethods(Assembly assembly)
        {
            Type[] types = assembly.GetTypes();
            List<MethodInfo> publicMethods = new List<MethodInfo>();

            foreach (Type type in types)
            {
                MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                publicMethods.AddRange(methods);
            }

            return publicMethods;
        }

        /// <summary>
        /// 获取指定程序集内指定类型的所有公共属性名称列表。
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="typeName">类型名称</param>
        /// <returns>属性名称列表</returns>
        public static List<string> GetPublicPropertyNames(Assembly assembly, string typeName)
        {
            Type? type = GetTypeFromAssembly(assembly, typeName);
            if (type != null)
            {
                PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                List<string> propertyNames = new List<string>();
                foreach (PropertyInfo property in properties)
                {
                    propertyNames.Add(property.Name);
                }
                return propertyNames;
            }
            return new List<string>();
        }

        /// <summary>
        /// 获取指定程序集内指定类型的所有公共字段名称列表。
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="typeName">类型名称</param>
        /// <returns>字段名称列表</returns>
        public static List<string> GetPublicFieldNames(Assembly assembly, string typeName)
        {
            Type? type = GetTypeFromAssembly(assembly, typeName);
            if (type != null)
            {
                FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                List<string> fieldNames = new List<string>();
                foreach (FieldInfo field in fields)
                {
                    fieldNames.Add(field.Name);
                }
                return fieldNames;
            }
            return new List<string>();
        }

        /// <summary>
        /// 获取指定程序集内指定类型的所有公共事件名称列表。
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="typeName">类型名称</param>
        /// <returns>事件名称列表</returns>
        public static List<string> GetPublicEventNames(Assembly assembly, string typeName)
        {
            Type? type = GetTypeFromAssembly(assembly, typeName);
            if (type != null)
            {
                EventInfo[] events = type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                List<string> eventNames = new List<string>();
                foreach (EventInfo eventInfo in events)
                {
                    eventNames.Add(eventInfo.Name);
                }
                return eventNames;
            }
            return new List<string>();
        }
    }
}
